import superagent from 'superagent'
import authMiddleware from '@/lib/auth-middleware'

function getSingleton(fn){
  let result
  return function(){
    return result || (result = fn.apply(this, arguments))
  }
}

function createToast(content){
  const ele = document.createElement("div")
  ele.className = "common-toast"
  ele.innerHTML = `<em>${content}</em>`
  document.body.appendChild(ele)
  return ele
}

export default {
  /**
   * common toast
   */
  toast: (function(){
    let instance, timer
    return function(content){
      if(instance){
        clearTimeout(timer)
        instance.style.display = 'block'
        instance.innerHTML = `<em>${content}</em>`
      } else {
        instance = createToast(content)
      }
      timer = setTimeout(() => {
        instance.style.display = 'none'
      }, 2000)
    }
  })(),

  /*
   * common modal
   */
  modal({ title, desc, callback }){
    const ele = document.createElement("div")
    const timeId = Date.now().valueOf()
    ele.className = "common-modal-wrapper"
    ele.id = `modal-id-${timeId}`
    ele.innerHTML = `<section class="common-modal">
                       <h1 class="modal-title">${title}</h1>
                       <p class="modal-desc">${desc}</p>
                       <ul class="modal-actions">
                         <li class="modal-confirm">确定</li>
                         <li class="modal-cancel">取消</li>
                       </ul>
                     </section>`
    const confirmEle = ele.querySelector('.modal-confirm')
    const cancelEle = ele.querySelector('.modal-cancel')
    confirmEle.addEventListener("click", function(){
      if(callback && typeof callback === 'function'){
        callback()
      }
      document.body.removeChild(ele)
    }, false)
    cancelEle.addEventListener("click", function(){
      document.body.removeChild(ele)
    }, false)

    document.body.appendChild(ele)
  },

  /**
   * get location.search key-value
   */
  getQueryString(name){
    const reg = new RegExp("(^|&)"+ name +"=([^&]*)(&|$)");
    const r = window.location.search.substr(1).match(reg);
    if(r!=null) return  decodeURIComponent(r[2]); return null;
  },

  /**
   * generateArray
   */
   generateArray(arr, num){
     let length = Math.ceil(arr.length/num),
         newArr = []
     for(let i = 0;i < length;i++){
       newArr[i] = arr.slice(i*num, (i+1)*num)
     }
     return newArr
   },

  /**
   * [os -- UA sniffer]
   * @method os
   * @param  {String} type [ios, android or weixin]
   * @return {Boolean}      [true or false]
   */
  os: (function(){
    let cache = {}
    return function(type){
      if(cache.hasOwnProperty(type)){
        return cache[type]
      }
      let ua = window.navigator.userAgent
      let reg
      switch (type) {
        case 'android':
          reg = /(Android);?[\s\/]+([\d.]+)?/
          break;
        case 'ios':
          reg = /(iPhone\sOS)\s([\d_]+)/
          break;
        case 'weixin':
          reg = /MicroMessenger/
      }
      if(!reg) return false

      let result = reg.test(ua)
      cache[type] = result
      return result
    }
  })(),

  /**
  * 频率控制 返回函数连续调用时，action 执行频率限定为 次 / delay
  * @param wait  {number}    延迟时间，单位毫秒
  * @param fn {function}  请求关联函数，实际应用需要调用的函数
  * @return {function}    返回客户调用函数
  */
  // throttle(fn, wait)
  throttle(fn, wait){
    let previous = 0,
        context,
        args,
        timer = null,
        result,
        later = function(){
          timer = null
          previous = Date.now()
          result = fn.apply(context, args)
          if(!timer) context = args = null
        }
    return function(){
      let remaining = wait - (Date.now() - previous)

      context = this
      args = arguments
      if(remaining <= 0 || remaining > wait){
        clearTimeout(timer)
        previous = Date.now()
        timer = null
        result = fn.apply(context, args)
        if(!timer) context = args = null
      } else if(!timer){
        timer = setTimeout(later, wait)
      }
      return result
    }
  },

  /**
  * 空闲控制 返回函数连续调用时，空闲时间必须大于或等于 idle，action 才会执行
  * @param fn {function}  请求关联函数，实际应用需要调用的函数
  * @param interval   {number}    空闲时间，单位毫秒
  * @param immediate {boolean}   设置为ture时，调用触发于开始边界而不是结束边界
  * @return {function}    返回客户调用函数
  */
  // debounce(fn, interval, immediate)

  debounce(fn, interval, immediate){
    let timer, previous, later, context, args, result

    later = function(){
      let last = Date.now() - previous

      if(last < interval && last > 0){
        timer = setTimeout(later, interval - last)
      } else {
        timer = null
        result = fn.apply(context, args)
        if(!timer) context = args = null
      }
    }
    return function(){
      context = this
      args = arguments
      previous = Date.now()

      if(!timer) {
        timer = setTimeout(later, interval)
      }
      return result
    }
  },

  checkLocator(){
    let result = window.location.href.replace(location.search, '').match(/(http:\/\/zplus\.tupppai\.com\/)(\??#\/)(.*)/)
    result.shift()
    if(result[1].indexOf('?') < 0){
      result[1] = '?' + result[1]
      let location = ''
      result.map(item => location += item)
      return location
    } else {
      return true
    }
  },

  requestFactory({ url, type = 'get', params = {} }){
    return function(){
      return new Promise((resolve, reject) => {
        superagent[type](url)
          .withCredentials()
          .use(authMiddleware())
          .query(params)
          // [(type === 'get' ? 'query':'send')](params)
          .end((err, res) => {
            if(res.ok && res.body){
              resolve(res.body.data)
            } else {
              let errorInfo = new Error()
              let { body: { info }, status } = res

              errorInfo.message = (info && info.length > 0 ? info:`request:${url} error`)
              errorInfo.status = status
              reject(errorInfo)
            }
          })
      })
    }
  },

  ObjectAssignPolyfill(){
    if (typeof Object.assign != 'function') {
      Object.assign = function(target) {
        'use strict';
        if (target == null) {
          throw new TypeError('Cannot convert undefined or null to object');
        }

        target = Object(target);
        for (var index = 1; index < arguments.length; index++) {
          var source = arguments[index];
          if (source != null) {
            for (var key in source) {
              if (Object.prototype.hasOwnProperty.call(source, key)) {
                target[key] = source[key];
              }
            }
          }
        }
        return target;
      };
    }
  },

  isArray(value){
    return Object.prototype.toString.call(value) === '[object Array]'
  },

  after(fn, afterFn){
    return function(){
      let res = fn.apply(this,arguments)
      if(res === 'next'){
        return afterFn.apply(this, arguments)
      }
      return res
    }
  }
}
